﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Collections.ObjectModel;
using System.Threading;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using GalaSoft.MvvmLight;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Globalization;

namespace YouTube.Model
{
    public class Model
    {

    }
    public delegate void PlayVideoCallBack(Exception error);
    public class NotifyPropertyChangedHelper : ViewModelBase, INotifyPropertyChanged
    {

    }
    public static class YouTubeXmlParser
    {
        // Fields
        private static XNamespace googleNamespace = "http://schemas.google.com/g/2005";
        private static XNamespace mediaNamespace = "http://search.yahoo.com/mrss/";
        private static XNamespace ns = "http://www.w3.org/2005/Atom";
        private static XNamespace youtubeNamespace = "http://gdata.youtube.com/schemas/2007";

        // Methods
        private static void ProcessMediaGroup(XElement data, VideoModel output)
        {
            XElement element = data.Element(youtubeNamespace + "videoid");
            output.VideoId = (string)element;
            XName name = mediaNamespace + "thumbnail";
            foreach (XElement element2 in data.Elements(name))
            {
                ThumbnailModel item = new ThumbnailModel();
                item.ReadFromXml(element2);
                output.Thumbnails.Add(item);
            }
            XName name2 = mediaNamespace + "content";
            foreach (XElement element3 in data.Elements(name2))
            {
                int num = (int)element3.Attribute(youtubeNamespace + "format");
                string uriString = (string)element3.Attribute("url");
                switch (num)
                {
                    case 3:
                        {
                            output.MediaContentUriFormat3 = new Uri(uriString);
                            continue;
                        }
                    case 2:
                        {
                            output.MediaContentUriFormat2 = new Uri(uriString);
                            continue;
                        }
                    case 9:
                        output.MediaContentUriFormat9 = new Uri(uriString);
                        break;
                }
            }
        }

        public static void ProcessVideo(Stream xmlstream, VideoModel model)
        {
            XmlReader reader = XmlReader.Create(xmlstream);
            XElement element = XElement.Load(reader);
            reader.Close();
            XElement element2 = element.Element(ns + "title");
            model.Title = (string)element2;
            ProcessMediaGroup(element.Element(mediaNamespace + "group"), model);
            model.ContentLoaded = true;
        }

        private static void ProcessVideo(XElement data, ObservableCollection<VideoModel> results)
        {
            VideoModel output = new VideoModel();
            XElement element = data.Element(ns + "title");
            output.Title = element.Value;
            ProcessMediaGroup(data.Element(mediaNamespace + "group"), output);
            output.ContentLoaded = true;
            results.Add(output);
        }

        public static void ProcessVideos(XElement data, ObservableCollection<VideoModel> results)
        {
            XName name = ns + "entry";
            foreach (XElement element in data.Elements(name))
            {
                ProcessVideo(element, results);
            }
        }
    }
    public class ThumbnailModel
    {
        // Fields
        private Uri contentUri;
        private int height;
        private string time;
        private int width;

        // Methods
        public void ReadFromXml(XElement data)
        {
            XAttribute attribute = data.Attribute("url");
            XAttribute attribute2 = data.Attribute("height");
            XAttribute attribute3 = data.Attribute("width");
            XAttribute attribute4 = data.Attribute("time");
            this.ContentUri = new Uri((string)attribute);
            this.Height = (int)attribute2;
            this.Width = (int)attribute3;
            if (attribute4 == null)
            {
                this.Time = "";
            }
            else
            {
                this.Time = attribute4.ToString() ?? string.Empty;
            }

        }

        // Properties
        public Uri ContentUri
        {
            get
            {
                return this.contentUri;
            }
            set
            {
                if (this.contentUri != value)
                {
                    this.contentUri = value;
                }
            }
        }

        public int Height
        {
            get
            {
                return this.height;
            }
            set
            {
                if (this.height != value)
                {
                    this.height = value;
                }
            }
        }

        public string Time
        {
            get
            {
                return this.time;
            }
            set
            {
                if (this.time != value)
                {
                    this.time = value;
                }
            }
        }

        public int Width
        {
            get
            {
                return this.width;
            }
            set
            {
                if (this.width != value)
                {
                    this.width = value;
                }
            }
        }
    }
    public class VideoId
    {
        // Fields

        private string id;

        // Methods
        public VideoId(string id)
        {
            this.Id = id;
        }

        // Properties
        public string Id
        {

            get
            {
                return this.id;
            }

            set
            {
                this.id = value;
            }
        }
    }
    public class VideoCache : KeyedCollection<string, VideoModel>
    {
        // Methods
        protected override string GetKeyForItem(VideoModel item)
        {
            return item.VideoId;
        }
    }
    public class VideoModel : NotifyPropertyChangedHelper
    {
        // Fields
        private bool contentLoaded;
        private Uri mediaContentUriFormat2;
        private Uri mediaContentUriFormat3;
        private Uri mediaContentUriFormat9;
        private EventHandler nModelLoaded;
        private List<ThumbnailModel> thumbnails = new List<ThumbnailModel>();
        private string title;
        private string videoid;

        // Events
        public event EventHandler OnModelLoaded
        {
            add
            {
                EventHandler handler2;
                EventHandler onModelLoaded = this.nModelLoaded;
                do
                {
                    handler2 = onModelLoaded;
                    EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
                    onModelLoaded = Interlocked.CompareExchange<EventHandler>(ref this.nModelLoaded, handler3, handler2);
                }
                while (onModelLoaded != handler2);
            }
            remove
            {
                EventHandler handler2;
                EventHandler onModelLoaded = this.nModelLoaded;
                do
                {
                    handler2 = onModelLoaded;
                    EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
                    onModelLoaded = Interlocked.CompareExchange<EventHandler>(ref this.nModelLoaded, handler3, handler2);
                }
                while (onModelLoaded != handler2);
            }
        }

        // Properties
        public ThumbnailModel BestThumbnail
        {
            get
            {
                int width = 0;
                ThumbnailModel model = null;
                ThumbnailModel model2 = null;
                foreach (ThumbnailModel model3 in this.thumbnails)
                {
                    if (model3.Width > width)
                    {
                        width = model3.Width;
                        model = model3;
                    }
                    if (string.IsNullOrEmpty(model3.Time))
                    {
                        model2 = model3;
                    }
                }
                if (model2 != null)
                {
                    model = model2;
                }
                return model;
            }
        }

        public bool ContentLoaded
        {
            get
            {
                return this.contentLoaded;
            }
            set
            {
                if (value != this.contentLoaded)
                {
                    this.contentLoaded = value;
                    base.RaisePropertyChanged("ContentLoaded");
                    if (value && (nModelLoaded != null))
                    {
                        nModelLoaded(this, null);
                    }
                }
            }
        }

        public Uri MediaContentUriFormat2
        {
            get
            {
                return this.mediaContentUriFormat2;
            }
            set
            {
                if (value != this.mediaContentUriFormat2)
                {
                    this.mediaContentUriFormat2 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat2");
                }
            }
        }

        public Uri MediaContentUriFormat3
        {
            get
            {
                return this.mediaContentUriFormat3;
            }
            set
            {
                if (value != this.mediaContentUriFormat3)
                {
                    this.mediaContentUriFormat3 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat3");
                }
            }
        }

        public Uri MediaContentUriFormat9
        {
            get
            {
                return this.mediaContentUriFormat9;
            }
            set
            {
                if (value != this.mediaContentUriFormat9)
                {
                    this.mediaContentUriFormat9 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat9");
                }
            }
        }

        public ThumbnailModel SmallestThumbnail
        {
            get
            {
                int width = 0x400;
                ThumbnailModel model = null;
                foreach (ThumbnailModel model2 in this.thumbnails)
                {
                    if (model2.Width < width)
                    {
                        width = model2.Width;
                        model = model2;
                    }
                }
                return model;
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists", Justification = "The assembly is not meant to be a reusable library.")]
        public List<ThumbnailModel> Thumbnails
        {
            get
            {
                return this.thumbnails;
            }
        }

        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if (value != this.title)
                {
                    this.title = value;
                    base.RaisePropertyChanged("Title");
                }
            }
        }

        public string VideoId
        {
            get
            {
                return this.videoid;
            }
            set
            {
                if (value != this.videoid)
                {
                    this.videoid = value;
                    base.RaisePropertyChanged("VideoId");
                }
            }
        }
    }
    public class YouTubeClient : NotifyPropertyChangedHelper, IDisposable
    {
        // Fields
        private const int DeviceRegistrationTimeout = 0x7530;
        private bool disposed;
        private static YouTubeClient instance;
        private ManualResetEvent registerDeviceComplete;
        private VideoCache videocache = new VideoCache();


        // Methods
        private YouTubeClient()
        {
            //  EventHandler callback = null;
            //  this.registerDeviceComplete = new ManualResetEvent(false);
            ////  this.videocache = new VideoCache();
            //  if (!DesignerProperties.IsInDesignTool)
            //  {
            //      if (callback == null)
            //      {
            //          callback = delegate(object x, EventArgs e)
            //          {
            //              this.registerDeviceComplete.Set();
            //          };
            //      }

            //  }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        Action<VideoModel> SCallback;
        public VideoModel GetVideoFromId(VideoId id, Action<VideoModel> callback, out bool synchronousAnswer)
        {
            
            if (this.videocache.Contains(id.Id))
            {
               synchronousAnswer = true;
                return this.videocache[id.Id];
            }
            synchronousAnswer = false;
            SCallback = callback;
            VideoModel vm = new VideoModel();
            vm.VideoId = id.Id;
            ThreadPool.QueueUserWorkItem(delegate(object unused)
            {
                OpenReadCompletedEventHandler handler2 = null;
                if (true)
                {
                    if (YouTubePrivateAPI.DeviceRegistered)
                    {
                        WebClient client = new WebClient();
                        string path = "/feeds/api/videos/" + id.Id + "?v=2";
                        string str2 = YouTubePrivateAPI.Signature(path);
                        client.Headers["X-GData-Device"] = str2;
                        Uri uri = new Uri("http://gdata.youtube.com" + path);
                        if (handler2 == null)
                        {
                            // handler2 = new OpenReadCompletedEventHandler(this, (IntPtr) this.<GetVideoFromId>b__3);
                        }
                        OpenReadCompletedEventHandler handler = handler2;


                        client.OpenReadCompleted += (s, e) =>
                        {
                            if (e.Result != null)
                            {
                                //  string ss = new StreamReader(e.Result).ReadToEnd();
                                YouTubeXmlParser.ProcessVideo(e.Result, vm);
                                SCallback(vm);
                            }
                        };
                        //  client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
                        client.OpenReadAsync(uri);
                    }
                    else if (callback != null)
                    {
                        // callback(YouTubePrivateAPI.DeviceRegistrationError);
                    }
                }
                else if (callback != null)
                {
                    //  callback(new WebException("Timeout when retrieving device registration information."));
                }
            });
            this.videocache.Add(vm);
            return vm;
        }
        public void GetTopRatedVideos(Action<ObservableCollection<VideoModel>> Callback)
        {
            https://gdata.youtube.com/feeds/api/standardfeeds/top_rated?time=today
            WebClient client = new WebClient();
            string path = "/feeds/api/standardfeeds/top_rated?time=today&orderby=published&start-index=1&max-results=10&v=2";


            string str2 = YouTubePrivateAPI.Signature(path);
            client.Headers["X-GData-Device"] = str2;
            Uri uri = new Uri("http://gdata.youtube.com" + path);

            client.OpenReadCompleted += (s, e) =>
            {
                if (e.Error != null)
                {
                    if (e.Result != null)
                    {
                        ObservableCollection<VideoModel> results = new ObservableCollection<VideoModel>();
                        // string ss = new StreamReader(e.Result).ReadToEnd();
                        XmlReader reader = XmlReader.Create(e.Result);
                        XElement element = XElement.Load(reader);
                        reader.Close();
                        YouTubeXmlParser.ProcessVideos(element, results);
                        if (Callback != null)
                            Callback(results);
                    }
                }
            };
            //  client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
            client.OpenReadAsync(uri);
        }
        public void getCategorisedVideo(string Category, Action<ObservableCollection<VideoModel>,string> callBack)
        {        https://gdata.youtube.com/feeds/api/videos?category=Music
            WebClient client = new WebClient();
        
        string path = "/feeds/api/videos?category=" +HttpUtility.HtmlEncode(Category) + "&start-index=1&max-results=10&v=2";


            string str2 = YouTubePrivateAPI.Signature(path);
            client.Headers["X-GData-Device"] = str2;
            Uri uri = new Uri("http://gdata.youtube.com" + path);

            client.OpenReadCompleted += (s, e) =>
            {
                try
                {
                    if (e.Result != null)
                    {
                        ObservableCollection<VideoModel> results = new ObservableCollection<VideoModel>();
                        // string ss = new StreamReader(e.Result).ReadToEnd();
                        XmlReader reader = XmlReader.Create(e.Result);
                        XElement element = XElement.Load(reader);
                        reader.Close();
                        YouTubeXmlParser.ProcessVideos(element, results);
                        if (callBack != null)
                            callBack(results, Category);
                    }
                }
                catch (Exception ex)
                {
                    callBack(null, "Error");
                }
            };
            //  client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
            client.OpenReadAsync(uri);
    
        }
        public void getViDeos(string keyword,Action<ObservableCollection<VideoModel>> Callback)
        {//orderby=published&

            WebClient client = new WebClient();
            string path = "/feeds/api/videos?q=" + keyword + "&start-index=1&max-results=10&v=2";


            string str2 = YouTubePrivateAPI.Signature(path);
            client.Headers["X-GData-Device"] = str2;
            Uri uri = new Uri("http://gdata.youtube.com" + path);

            client.OpenReadCompleted += (s, e) =>
            {
                if (e.Result != null)
                {
                    ObservableCollection<VideoModel> results = new ObservableCollection<VideoModel>();
                    // string ss = new StreamReader(e.Result).ReadToEnd();
                    XmlReader reader = XmlReader.Create(e.Result);
                    XElement element = XElement.Load(reader);
                    reader.Close();
                    YouTubeXmlParser.ProcessVideos(element, results);
                   if(Callback!=null)
                    Callback(results);
                }
            };
            //  client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
            client.OpenReadAsync(uri);
        }
        void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                string s = new StreamReader(e.Result).ReadToEnd();

                //  SCallback(s);

            }

        }

        private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    this.registerDeviceComplete.Close();
                }
                this.disposed = true;
            }
        }



        // Properties
        public static YouTubeClient Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new YouTubeClient();
                }
                return instance;
            }
        }
        public Action Callback;
        public void getvideo(Action callback)
        {
            Callback = callback;
            YouTubePrivateAPI.EnsureDeviceRegistered(Callback);
        }
        public void RegisterDevice(Action callback)
        {
            Callback = callback;
            YouTubePrivateAPI.EnsureDeviceRegistered(Callback);
        }
    }
    public class VideoViewModel : NotifyPropertyChangedHelper
    {
        // Fields
        private bool contentLoaded;
        private bool imagesLoaded;
        private Uri mediaContentUriFormat2;
        private Uri mediaContentUriFormat3;
        private Uri mediaContentUriFormat9;
        private VideoModel model;
        private BitmapImage thumbnail;
        private string title;
        private string videoid;

        // Methods
        public VideoViewModel()
        {
            if (DesignerProperties.IsInDesignTool)
            {
                this.AddDummyData();
            }
        }

        public VideoViewModel(VideoModel model)
        {
            if (model != null)
            {
                this.model = model;
                model.PropertyChanged += new PropertyChangedEventHandler(this.Model_PropertyChanged);
                this.PopulateFromModel(model);
            }
            this.contentLoaded = true;
        }

        private void AddDummyData()
        {
            this.Title = "Obama vs B.P.";
            Uri uriSource = new Uri("http://i3.ytimg.com/vi/f6ejKtZrsxY/default.jpg");
            BitmapImage image = new BitmapImage(uriSource);
            this.Thumbnail = image;
            this.contentLoaded = true;
            this.imagesLoaded = true;
        }

        private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.PopulateFromModel(this.model);
        }

        private void OnBitmapLoaded(object sender, RoutedEventArgs e)
        {
            this.ImagesLoaded = true;
        }

        private void PopulateFromModel(VideoModel model)
        {
            if ((model != null) && model.ContentLoaded)
            {
                this.model = model;
                this.VideoId = model.VideoId;
                this.Title = model.Title;
                ThumbnailModel bestThumbnail = model.BestThumbnail;
                if (bestThumbnail != null)
                {
                    this.Thumbnail = new BitmapImage();
                    this.thumbnail.ImageOpened += new EventHandler<RoutedEventArgs>(this.OnBitmapLoaded);
                    this.Thumbnail.UriSource = bestThumbnail.ContentUri;
                }
                this.MediaContentUriFormat2 = model.MediaContentUriFormat2;
                this.MediaContentUriFormat3 = model.MediaContentUriFormat3;
                this.MediaContentUriFormat9 = model.MediaContentUriFormat9;
            }
        }

        private static string ToTimeString(int numSeconds)
        {
            return TimeSpan.FromSeconds((double)numSeconds).ToString();
        }

        // Properties
        public bool ContentLoaded
        {
            get
            {
                return this.contentLoaded;
            }
            set
            {
                if (value != this.contentLoaded)
                {
                    this.contentLoaded = value;
                    base.RaisePropertyChanged("ContentLoaded");
                }
            }
        }

        public bool ImagesLoaded
        {
            get
            {
                return this.imagesLoaded;
            }
            set
            {
                if (value != this.imagesLoaded)
                {
                    this.imagesLoaded = value;
                    base.RaisePropertyChanged("ImagesLoaded");
                }
            }
        }

        public Uri MediaContentUriFormat2
        {
            get
            {
                return this.mediaContentUriFormat2;
            }
            set
            {
                if (value != this.mediaContentUriFormat2)
                {
                    this.mediaContentUriFormat2 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat2");
                }
            }
        }

        public Uri MediaContentUriFormat3
        {
            get
            {
                return this.mediaContentUriFormat3;
            }
            set
            {
                if (value != this.mediaContentUriFormat3)
                {
                    this.mediaContentUriFormat3 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat3");
                }
            }
        }

        public Uri MediaContentUriFormat9
        {
            get
            {
                return this.mediaContentUriFormat9;
            }
            set
            {
                if (value != this.mediaContentUriFormat9)
                {
                    this.mediaContentUriFormat9 = value;
                    base.RaisePropertyChanged("MediaContentUriFormat9");
                }
            }
        }

        public VideoModel Model
        {
            get
            {
                return this.model;
            }
            set
            {
                if (this.model != value)
                {
                    this.model = value;
                    this.model.PropertyChanged += new PropertyChangedEventHandler(this.Model_PropertyChanged);
                    this.PopulateFromModel(this.model);
                    base.RaisePropertyChanged("Model");
                }
            }
        }

        public BitmapImage Thumbnail
        {
            get
            {
                return this.thumbnail;
            }
            set
            {
                if (value != this.thumbnail)
                {
                    this.thumbnail = value;
                    base.RaisePropertyChanged("Thumbnail");
                }
            }
        }

        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if (value != this.title)
                {
                    this.title = value;
                    base.RaisePropertyChanged("Title");
                }
            }
        }

        public string VideoId
        {
            get
            {
                return this.videoid;
            }
            set
            {
                if (value != this.videoid)
                {
                    this.videoid = value;
                    base.RaisePropertyChanged("VideoId");
                }
            }
        }
    }
    public class PlayVideoViewModel : NotifyPropertyChangedHelper
    {
        // Fields
        private TimeSpan duration;
        private TimeSpan position;
        private string status = string.Empty;

        // Methods
        private static string ToTimeString(int numSeconds)
        {
            TimeSpan span = TimeSpan.FromSeconds((double)numSeconds);
            if (((int)span.TotalHours) > 0)
            {
             //   return string.Format(CultureInfo.InvariantCulture, Strings.DurationFormatWithHours, new object[] { (int)span.TotalHours, span.Minutes, span.Seconds });
            }
            //return string.Format(CultureInfo.InvariantCulture, Strings.DurationFormatNoHours, new object[] { span.Minutes, span.Seconds });
            return "";
        }

        // Properties
        public TimeSpan Duration
        {
            get
            {
                return this.duration;
            }
            set
            {
                if (this.duration != value)
                {
                    this.duration = value;
                }
                base.RaisePropertyChanged("PositionAndDuration");
            }
        }

        public TimeSpan Position
        {
            get
            {
                return this.position;
            }
            set
            {
                if (this.position != value)
                {
                    this.position = value;
                }
                base.RaisePropertyChanged("PositionAndDuration");
            }
        }

        public string PositionAndDuration
        {
            get
            {
                TimeSpan duration = this.Duration;
                TimeSpan position = this.Position;
                string str = ToTimeString((int)this.Position.TotalSeconds);
                string str2 = ToTimeString((int)this.Duration.TotalSeconds);
                return string.Format(CultureInfo.CurrentCulture, "{0}/{1}", new object[] { str, str2 });
            }
        }

        public string Status
        {
            get
            {
                return this.status;
            }
            set
            {
                if (this.status != value)
                {
                    this.status = value;
                }
                base.RaisePropertyChanged("Status");
            }
        }
    }


}
